#include "RenderMaster.h"
#include "../Event System/EventManager.h"
#include "../Event System/Event.h"
#include "../Game Objects/BaseObject.h"

#include "../AnimConfig.h"

#if _DEBUG
#include "../Game.h"
#include "../Debug Console/DebugConsole.h"
#endif

////////////////////////////////
// REMOVE THIS OBVIOUSLY!
static float globalRotate = 30.0f;
////////////////////////////////

//////////////////////////////////////
// Structures
//////////////////////////////////////

// A vertex for the screen quad
struct TScreenQuadVert
{
	D3DXVECTOR3 vPosition;
	D3DXVECTOR2 vTexCoord;
};

	
CRenderMaster::CRenderMaster( void )
{

}

void CRenderMaster::Initialize( HWND hWnd, char* szShaderFile )
{
	///////////////////////////
	// Set up render functions

	///////////////////////////
	// DirectX mumbo jumbo
	m_pD3D = Direct3DCreate9( D3D_SDK_VERSION );

	// Present parameters
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory( &d3dpp, sizeof( D3DPRESENT_PARAMETERS ) );
	
	d3dpp.hDeviceWindow				= hWnd;
	d3dpp.Windowed					= TRUE;
	d3dpp.PresentationInterval		= D3DPRESENT_INTERVAL_IMMEDIATE;
	d3dpp.SwapEffect				= D3DSWAPEFFECT_DISCARD;
	d3dpp.EnableAutoDepthStencil	= TRUE;
	d3dpp.AutoDepthStencilFormat	= D3DFMT_D16;

	m_pD3D->CreateDevice( 0, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &m_pDev );

	//////////////////////////////
	// Register for events!!!
	RegisterEvents( );

	//////////////////////////////
	// Initialize deferred shading
	InitDeferred( );

	/////////////////////////////
	// Build a sphere
	InitDebugShapes( );

	//////////////////////////
	// Load all of the shaders
	m_AssetManager.Initialize( m_pDev );
	m_AssetManager.LoadShaders( szShaderFile );

	////////////////////////
	// Initialize the camera
	m_Camera.BuildPerspective( );
	m_Camera.SetViewPositionAxis( D3DXVECTOR3( 0.0f, 0.0f, 10.0f ) );

	InitPractice( );

	m_AssetManager.LoadAnimatedMesh( "root/resource/models/BandicootShape.mow" );
}

CRenderMaster::~CRenderMaster( void )
{

}
void CRenderMaster::RegisterEvents( void )
{
	CEventManager::GetInstance( )->RegisterForEventInRender( EVENT_RENDER, this );
}
void CRenderMaster::UnregisterEvents( void )
{
	CEventManager::GetInstance( )->UnregisterForEventInRender( EVENT_RENDER, this );
}
void CRenderMaster::InitPractice( void )
{
	D3DVERTEXELEMENT9 practiceDecl[ ] = 
	{
		{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
		{ 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
		{ 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
		{ 0, 32, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0 },
		{ 0, 44, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0 },

		D3DDECL_END( )
	};
	m_pDev->CreateVertexDeclaration( practiceDecl, &m_pPracticeDecl );

	/////////////////////////
	// Load in the debug shader
	ID3DXBuffer* pErrors = NULL;
	D3DXCreateEffectFromFile( m_pDev, "Root/Resource/Shaders/GBufferAnim.fx", 0, 0, D3DXSHADER_DEBUG, 0, &m_pInsertShaderHere, &pErrors );

	#if _DEBUG
	if( pErrors != NULL )
		CGame::GetInstance( )->GetConsole( )->Display( ( char* )pErrors->GetBufferPointer( ) );
	#endif
}
void CRenderMaster::InitDebugShapes( void )
{
	////////////////////////
	// Sphere

	// Create the mesh
	D3DXCreateSphere( m_pDev, 1.0f, 18, 9, &m_pSphereMesh, NULL );

	// Get all the mesh's information to use later
	m_pSphereMesh->GetVertexBuffer( &m_pSphereVerts );
	m_pSphereMesh->GetIndexBuffer( &m_pSphereIndices );
	
	m_unSphereVertSize = m_pSphereMesh->GetNumBytesPerVertex( );
	m_unNumSphereVerts = m_pSphereMesh->GetNumVertices( );
	m_unNumSphereTris = m_pSphereMesh->GetNumFaces( );

	/////////////////////////
	// Cylinder
	D3DXCreateCylinder( m_pDev, 1.0f, 1.0f, 1.0f, 20, 10, &m_pCylinderMesh, NULL );

	// Get all the mesh's information to use later
	m_pCylinderMesh->GetVertexBuffer( &m_pCylinderVerts );
	m_pCylinderMesh->GetIndexBuffer( &m_pCylinderIndices );
	
	m_unCylinderVertSize = m_pCylinderMesh->GetNumBytesPerVertex( );
	m_unNumCylinderVerts = m_pCylinderMesh->GetNumVertices( );
	m_unNumCylinderTris = m_pCylinderMesh->GetNumFaces( );
	/////////////////////////

	D3DVERTEXELEMENT9 positionDecl[ ] = 
	{
		{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
		D3DDECL_END( )
	};
	m_pDev->CreateVertexDeclaration( positionDecl, &m_pShapesDecl );

	/////////////////////////
	// Load in the debug shader
	ID3DXBuffer* pErrors = NULL;
	D3DXCreateEffectFromFile( m_pDev, "Root/Resource/Shaders/DebugShapes.fx", 0, 0, D3DXSHADER_DEBUG, 0, &m_pDebugShapes, &pErrors );

	#if _DEBUG
	if( pErrors != NULL )
		CGame::GetInstance( )->GetConsole( )->Display( ( char* )pErrors->GetBufferPointer( ) );
	#endif

}
void CRenderMaster::InitDeferred( void )
{
	// Initialize the shaders and render targets
	InitDeferredShaders( );
	InitRenderTargets( );

	// Vert declaration for screen quad
	D3DVERTEXELEMENT9 vertDecl[ ] = 
	{
		{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
		{ 0,12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
		D3DDECL_END( )
	};
	m_pDev->CreateVertexDeclaration( vertDecl, &m_pSceneQuadDecl );
	
	// The render quad's verts
	TScreenQuadVert verts[6];
	verts[0].vPosition.x = -1.0f;	verts[0].vPosition.y = 1.0f;		verts[0].vPosition.z = 0.0f;
	verts[1].vPosition.x = 1.0f;		verts[1].vPosition.y = 1.0f;		verts[1].vPosition.z = 0.0f;
	verts[2].vPosition.x = 1.0f;		verts[2].vPosition.y = -1.0f;	verts[2].vPosition.z = 0.0f;
	verts[3].vPosition.x = 1.0f;		verts[3].vPosition.y = -1.0f;	verts[3].vPosition.z = 0.0f;
	verts[4].vPosition.x = -1.0f;	verts[4].vPosition.y = -1.0f;	verts[4].vPosition.z = 0.0f;
	verts[5].vPosition.x = -1.0f;	verts[5].vPosition.y = 1.0f;		verts[5].vPosition.z = 0.0f;

	verts[0].vTexCoord.x = 0.0f;	verts[0].vTexCoord.y = 0.0f;
	verts[1].vTexCoord.x = 1.0f;	verts[1].vTexCoord.y = 0.0f;
	verts[2].vTexCoord.x = 1.0f;	verts[2].vTexCoord.y = 1.0f;
	verts[3].vTexCoord.x = 1.0f;	verts[3].vTexCoord.y = 1.0f;
	verts[4].vTexCoord.x = 0.0f;	verts[4].vTexCoord.y = 1.0f;
	verts[5].vTexCoord.x = 0.0f;	verts[5].vTexCoord.y = 0.0f;

	// Make the vertex buffer
	m_pDev->CreateVertexBuffer( 6 * sizeof( TScreenQuadVert ), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &m_pSceneQuadVerts, 0 );

	// Copy the vert information into the vert buffer
	void* pVertBuffer;
	m_pSceneQuadVerts->Lock( 0, 0, &pVertBuffer, 0 );
	memcpy( pVertBuffer, verts, 6 * sizeof( TScreenQuadVert ) );
	m_pSceneQuadVerts->Unlock( );
	
	// Grab the back buffer to render to later
	m_pDev->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer );
}

void CRenderMaster::InitDeferredShaders( void )
{
	ID3DXBuffer* pErrors = NULL;
	// Load in the shader to clear the GBuffer
	D3DXCreateEffectFromFile( m_pDev, "Root/Resource/Shaders/Clear.fx", 0, 0, D3DXSHADER_DEBUG, 0, &m_pClearShader, &pErrors );

	// Check for errors
	#if _DEBUG
	if( pErrors != NULL )
		CGame::GetInstance( )->GetConsole( )->Display( ( char* )pErrors->GetBufferPointer( ) );
	#endif
		
	// Load in the directional light shader
	D3DXCreateEffectFromFile( m_pDev, "Root/Resource/Shaders/DirectionalLight.fx", 0, 0, D3DXSHADER_DEBUG, 0, &m_pDirectLightShader, &pErrors );
	
	// Check for errors
	#if _DEBUG
	if( pErrors != NULL )
		CGame::GetInstance( )->GetConsole( )->Display( ( char* )pErrors->GetBufferPointer( ) );
	#endif
		
	// Load in the point light shader
	D3DXCreateEffectFromFile( m_pDev, "Root/Resource/Shaders/PointLight.fx", 0, 0, D3DXSHADER_DEBUG, 0, &m_pPointLightShader, &pErrors );
	
	// Check for errors
	#if _DEBUG
	if( pErrors != NULL )
		CGame::GetInstance( )->GetConsole( )->Display( ( char* )pErrors->GetBufferPointer( ) );
	#endif
		
	// Load in the final shader
	D3DXCreateEffectFromFile( m_pDev, "Root/Resource/Shaders/PostProcess.fx", 0, 0, D3DXSHADER_DEBUG, 0, &m_pPostProcessShader, &pErrors );

	// Check for errors
	#if _DEBUG
	if( pErrors != NULL )
		CGame::GetInstance( )->GetConsole( )->Display( ( char* )pErrors->GetBufferPointer( ) );
	#endif
}

void CRenderMaster::InitRenderTargets( void )
{
	// Create a texture for the color information to render to
	HRESULT hr = m_pDev->CreateTexture( 1024, 720, 0, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pColorTexture, NULL );
	hr = m_pColorTexture->GetSurfaceLevel( 0, &m_pColorSurface );

	// Create a texture to render the normal info to
	hr = m_pDev->CreateTexture( 1024, 720, 0, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pNormalTexture, NULL );
	hr = m_pNormalTexture->GetSurfaceLevel( 0, &m_pNormalSurface );
		
	// Create a texture to render the depth info to
	hr = m_pDev->CreateTexture( 1024, 720, 0, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pDepthTexture, NULL );
	hr = m_pDepthTexture->GetSurfaceLevel( 0, &m_pDepthSurface );

	// Create a texture and surface to render the light to
	hr = m_pDev->CreateTexture( 1024, 720, 0, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pLightTexture, NULL );
	hr = m_pLightTexture->GetSurfaceLevel( 0, &m_pLightSurface );
}

void CRenderMaster::Render( TRenderNode* pRootNode )
{	
	// REMOVE THIS!!
	//globalRotate += 0.0005f;

	TRenderNode* pCurrentNode = pRootNode;

	/////////////////////
	// Begin to render !
	m_pDev->BeginScene( );

	m_pDev->SetRenderTarget( 0, m_pColorSurface );
	m_pDev->SetRenderTarget( 1, m_pNormalSurface );
	m_pDev->SetRenderTarget( 2, m_pDepthSurface );

	m_pDev->Clear( 0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB( 0, 255, 0 ), 1.0f, 0 );

	// Necessary?
	m_pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );


	PracticeRender( );
	// RenderCargo( );
	// RenderEnemies( );
	// RenderPlayerTurrets( );
	// RenderEnvironment( );
	

	// REMOVE THIS
	// DRAWTROGDOR( );

	//for( unsigned int i = 0; i < 10; ++i )
	//	RenderShape( D3DXVECTOR3( ( float )i, ( float )i, 0.0f ), 1.5f, SHAPE_SPHERE );

	//for( unsigned int i = 0; i < 10; ++i )
		//RenderShape( D3DXVECTOR3( ( float )i, ( float )i - 2.0f, 0.0f ), 0.5f, SHAPE_CYLINDER );

	RenderLights( );

	// Get INPUT!!!! REMOVE THIS
	GetInput( );

	m_pDev->SetRenderTarget( 0, m_pBackBuffer );
	
	CombineFinalImage( );

	// We're done drawing so we can show what we've done!
	m_pDev->EndScene( );
	m_pDev->Present( 0, 0, 0, 0 );
	// End Rendering
	///////////////////
}

void CRenderMaster::RenderShape( D3DXVECTOR3 vPosition, float fRadius, PRIMITIVE shape )
{
	if( m_pDebugShapes )
	{
		// Begin the shader!
		m_pDebugShapes->SetTechnique( "Basic" );
		unsigned int nNumPasses = 0;
		m_pDebugShapes->Begin( &nNumPasses, 0 );

		// Orient shape to match owner
		D3DXMATRIX mScale, mTranslation;
		D3DXMatrixScaling( &mScale, fRadius, fRadius, fRadius );
		D3DXMatrixTranslation( &mTranslation, vPosition.x, vPosition.y, vPosition.z );

		// Loop through the passes
		for( unsigned int i = 0; i < nNumPasses; ++i )
		{
			m_pDebugShapes->BeginPass( i );

			// Send any data to the shader
			m_pDebugShapes->SetMatrix( "gWVP", &( ( mScale * mTranslation ) * m_Camera.GetView( ) * m_Camera.GetProjection( ) ) );
			m_pDebugShapes->SetVector( "gColor", &D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 1.0f ) );
			m_pDebugShapes->CommitChanges( );

			m_pDev->SetVertexDeclaration( m_pShapesDecl );

			// It's shape determines the vert/index data
			if( shape == SHAPE_SPHERE )
			{
				m_pDev->SetStreamSource( 0, m_pSphereVerts, 0, m_unSphereVertSize );
				m_pDev->SetIndices( m_pSphereIndices );
				m_pDev->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, m_unNumSphereVerts, 0, m_unNumSphereTris );
			}
			else
			{
				m_pDev->SetStreamSource( 0, m_pCylinderVerts, 0, m_unCylinderVertSize );
				m_pDev->SetIndices( m_pCylinderIndices );
				m_pDev->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, m_unNumCylinderVerts, 0, m_unNumCylinderTris );
			}

			// Complete the pass
			m_pDebugShapes->EndPass( );
		}

		// We're done with the shader!
		m_pDebugShapes->End( );
	}
}


void CRenderMaster::PracticeRender( void )
{
	if( m_Bandicoot.IsEmpty( ) )
		return;

	// If the shader is valid jump on in
	if( m_pInsertShaderHere )
	{
		m_pInsertShaderHere->SetTechnique( "Basic" );

		unsigned int unPasses;
		m_pInsertShaderHere->Begin( &unPasses, 0 );

		// Set everything that wont change between objects
		m_pDev->SetVertexDeclaration( m_pPracticeDecl );

		SLLIter<CBaseObject*> m_BandiIter( m_Bandicoot );
		m_BandiIter.begin( );

		// Iterate through the list of objects
		while( !m_BandiIter.end( ) )
		{
			for( unsigned int i = 0; i < unPasses; ++i )
			{
				m_pInsertShaderHere->BeginPass( i );

				TAnimMesh* pMesh = ( TAnimMesh* )m_AssetManager.GetMesh( m_BandiIter.current( )->GetType( ) );

				m_pDev->SetStreamSource( 0, pMesh->pVertBuffer, 0, sizeof( TANIMVERTEX ) );
				m_pDev->SetIndices( pMesh->pIndexBuffer );

				m_pInsertShaderHere->SetMatrixArray( "gBindPose", pMesh->BindPose, MAX_JOINTS );

				// TAKE THIS OUT, SHOULD BE THE LIST OF JOINTS FROM MESSAGE///////////////////
				D3DXMATRIX joints[MAX_JOINTS];												//
				for(int joint = 0; joint < MAX_JOINTS; ++joint)								//
				{
					D3DXMatrixInverse(&joints[joint], NULL, &pMesh->BindPose[joint]);		//
				}
				m_pInsertShaderHere->SetMatrixArray( "gCurrentPose", joints, MAX_JOINTS );	//
				//////////////////////////////////////////////////////////////////////////////

				// Set everything that will change between objects
				m_pInsertShaderHere->SetMatrix( "gWVP", &( m_BandiIter.current()->GetOrientation() * m_Camera.GetView( ) * m_Camera.GetProjection( ) ) );
				m_pInsertShaderHere->SetMatrix( "World", &m_BandiIter.current()->GetOrientation() );
				
				D3DXMATRIX identity;
				D3DXMatrixIdentity(&identity);
				m_pInsertShaderHere->SetMatrix( "World",&identity);
		
				// Things have been changed so lets tell the shader
				m_pInsertShaderHere->CommitChanges( );

				// Pretty much all we do is draw it in it's new position
				m_pDev->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, pMesh->nNumVerts, 0, pMesh->nNumTris );

				m_pInsertShaderHere->EndPass( );
			}

			++m_BandiIter;
			//pCurrNode = pCurrNode->pNext;
		}

		// We're done with this shader
		m_pInsertShaderHere->End( );
	}
}
void CRenderMaster::RenderLights( void )
{
	// Render all of the light information to the correct render target
	HRESULT hr = m_pDev->SetRenderTarget( 0, m_pLightSurface );
	m_pDev->SetRenderTarget( 1, NULL );
	m_pDev->SetRenderTarget( 2, NULL );

	hr = m_pDev->Clear( 0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 0 ), 1.0f, 0 );

	// Are these necessary ??
	hr = m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
	hr = m_pDev->SetRenderState( D3DRS_ALPHAFUNC, D3DBLENDOP_ADD );
	hr = m_pDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
	hr = m_pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
	hr = m_pDev->SetRenderState( D3DRS_SEPARATEALPHABLENDENABLE, TRUE );

	 //RenderDirectionalLight( D3DXVECTOR3( -1.0f, -1.0f, 0.0f ), D3DXVECTOR4( 0.0f, 0.0f, 1.0f, 0.0f ) );
	 RenderDirectionalLight( D3DXVECTOR3( 0.0f, -1.0f, 0.0f ), D3DXVECTOR4( 1.0f, 1.0f, 1.0f, 0.0f ) );
	 //RenderDirectionalLight( D3DXVECTOR3( 1.0f, -1.0f, 0.0f ), D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 0.0f ) );

	/*RenderPointLight( D3DXVECTOR3( 0.0f, 0.0f, 1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 1.0f, 1.0f ), 5.0f, 4.0f );
	RenderPointLight( D3DXVECTOR3( 1.0f, 0.0f, 0.0f ), D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 1.0f ), 5.0f, 4.0f );
	RenderPointLight( D3DXVECTOR3( -1.0f, 0.0f, 1.0f ), D3DXVECTOR4( 0.0f, 1.0f, 0.0f, 1.0f ), 5.0f, 4.0f );
	RenderPointLight( D3DXVECTOR3( 0.0f, 0.0f, -1.0f ), D3DXVECTOR4( 0.0f, 0.0f, 1.0f, 1.0f ), 5.0f, 4.0f );
	RenderPointLight( D3DXVECTOR3( 0.0f, 1.0f, 0.0f ), D3DXVECTOR4( 1.0f, 0.0f, 1.0f, 1.0f ), 5.0f, 4.0f );*/
}
void CRenderMaster::RenderDirectionalLight( D3DXVECTOR3 vLightDir, D3DXVECTOR4 vColor )
{
	// If the shader is loaded correctly
	if( m_pDirectLightShader )
	{
		D3DXVECTOR4 lightDir( vLightDir,1.0f );

		// Start the shader
		m_pDirectLightShader->SetTechnique( "Basic" );
		unsigned int nNumPasses = 0;
		m_pDirectLightShader->Begin( &nNumPasses, 0 );

		// Loop through the number of passes
		for( unsigned int i = 0; i < nNumPasses; ++i )
		{
			// Begin current pass
			m_pDirectLightShader->BeginPass( i );

			// Set all needed variables
			m_pDirectLightShader->SetVector( "lightDirection", &lightDir);
			m_pDirectLightShader->SetVector( "color", &vColor );
			m_pDirectLightShader->SetTexture( "colortex", m_pColorTexture );
			m_pDirectLightShader->SetTexture( "normaltex", m_pNormalTexture );
			m_pDirectLightShader->SetTexture( "depthtex", m_pDepthTexture );
			// Apply all the specific variables
			m_pDirectLightShader->CommitChanges( );

			// Set the appropriate vertex info
			m_pDev->SetVertexDeclaration( m_pSceneQuadDecl );
			m_pDev->SetStreamSource( 0, m_pSceneQuadVerts, 0, sizeof( TScreenQuadVert ) );
			m_pDev->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );

			// End the current pass
			m_pDirectLightShader->EndPass( );
		}

		// End the current shader
		m_pDirectLightShader->End( );
	}
}
void CRenderMaster::RenderPointLight( D3DXVECTOR3 vPosition, D3DXVECTOR4 vColor, float fRadius, float fIntensity )
{
	// If the shader is loaded correctly
	if( m_pPointLightShader )
	{
		// Build the light
		D3DXMATRIX ScaledMat, TranslateMat, WorldMat, InvertViewProj;
		D3DXMatrixIdentity( &ScaledMat );
		D3DXMatrixScaling( &ScaledMat, fRadius, fRadius, fRadius );
		D3DXMatrixTranslation( &TranslateMat, vPosition.x, vPosition.y, vPosition.z );
		D3DXMatrixMultiply( &WorldMat, &ScaledMat, &TranslateMat );

		// Calculate the inverted View Projection matrix
		//D3DXMatrixInverse( &InvertViewProj, NULL, &( m_Camera.GetView( ) * m_Camera.GetProjection( ) ) );
		InvertViewProj = m_Camera.GetViewProjection();

		// Set the technique according to distance
		float fDistance = D3DXVec3Length( &( m_Camera.GetViewPositionAxis( ) - vPosition ) );
		if( fDistance < fRadius )
			m_pPointLightShader->SetTechnique( "BasicCW" );
		else
			m_pPointLightShader->SetTechnique( "BasicCCW" );


		// Begin the shader effect
		unsigned int nNumPasses = 0;
		m_pPointLightShader->Begin( &nNumPasses, 0 );

		// Loop through for the proper number of passes
		for( unsigned int i = 0; i < nNumPasses; ++i )
		{
			// Begin the current pass
			m_pPointLightShader->BeginPass( i );
			
			// Set all the needed variables
			m_pPointLightShader->SetMatrix( "World", &WorldMat );
			m_pPointLightShader->SetMatrix( "View", &m_Camera.GetView( ) );
			m_pPointLightShader->SetMatrix( "Projection", &m_Camera.GetProjection( ) );
			m_pPointLightShader->SetMatrix( "InvertViewProjection", &InvertViewProj );

			m_pPointLightShader->SetVector( "lightPosition", &D3DXVECTOR4( vPosition, 1.0f ) );
			m_pPointLightShader->SetVector( "color", &vColor );

			m_pPointLightShader->SetFloat( "lightRadius", fRadius );
			m_pPointLightShader->SetFloat( "lightIntensity", fIntensity );

			m_pPointLightShader->SetTexture( "normaltex", m_pNormalTexture );
			m_pPointLightShader->SetTexture( "depthtex", m_pDepthTexture );

			// Apply the changed variables
			m_pPointLightShader->CommitChanges( );

			// RECT scissorRect = {
			// m_pDev->SetScissorRect(
			m_pDev->SetStreamSource( 0, m_pSphereVerts, 0, m_unSphereVertSize );
			m_pDev->SetIndices( m_pSphereIndices );
			m_pDev->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, m_unNumSphereVerts, 0, m_unNumSphereTris );

			// End current pass
			m_pPointLightShader->EndPass( );
		}

		// And so the shader is no more
		m_pPointLightShader->End( );
	}
}


void CRenderMaster::CombineFinalImage( void )
{
	if( m_pPostProcessShader )
	{
		m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );

		m_pPostProcessShader->SetTechnique( "Basic" );
		unsigned int nPasses = 0;
		m_pPostProcessShader->Begin( &nPasses, 0 );

		m_pPostProcessShader->SetTexture( "color", m_pColorTexture );
		m_pPostProcessShader->SetTexture( "light", m_pLightTexture );

		for( unsigned int i = 0; i < nPasses; ++i )
		{
			m_pPostProcessShader->BeginPass( i );
			
			m_pDev->SetVertexDeclaration( m_pSceneQuadDecl );
			m_pDev->SetStreamSource( 0, m_pSceneQuadVerts, 0, sizeof( TScreenQuadVert ) );
			m_pDev->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );

			m_pPostProcessShader->EndPass( );
		}

		m_pPostProcessShader->End( );
	}
}

void CRenderMaster::ClearGBuffer( void )
{
	if( m_pClearShader )
	{
		m_pClearShader->SetTechnique( "Basic" );
		unsigned int nPasses = 0;
		m_pClearShader->Begin( &nPasses, 0 );

		for( unsigned int i = 0; i < nPasses; ++i )
		{
			m_pClearShader->BeginPass( i );
			
			m_pDev->SetVertexDeclaration( m_pSceneQuadDecl );
			m_pDev->SetStreamSource( 0, m_pSceneQuadVerts, 0, sizeof( TScreenQuadVert ) );
			m_pDev->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );

			m_pClearShader->EndPass( );
		}

		m_pClearShader->End( );
	}
}


void CRenderMaster::ProcessEvent( CEvent* pEvent )
{
	switch( pEvent->GetEventID( ) )
	{
		case EVENT_RENDER:
			// Grab the root node of the list from the event
			m_Bandicoot = ( ( RenderEvent* )pEvent->GetData( ) )->GetList( );
		break;
	};

	pEvent->SubtractRef( );
}
void CRenderMaster::ShutdownDeferred( void )
{
	RELEASE_DRX( m_pClearShader );
	RELEASE_DRX( m_pDirectLightShader );
	RELEASE_DRX( m_pPointLightShader );
	RELEASE_DRX( m_pPostProcessShader );

	RELEASE_DRX( m_pColorSurface );
	RELEASE_DRX( m_pColorTexture );

	RELEASE_DRX( m_pNormalSurface );
	RELEASE_DRX( m_pNormalTexture );

	RELEASE_DRX( m_pDepthSurface );
	RELEASE_DRX( m_pDepthTexture );

	RELEASE_DRX( m_pLightSurface );
	RELEASE_DRX( m_pLightTexture );

	RELEASE_DRX( m_pSceneQuadDecl );
	RELEASE_DRX( m_pSceneQuadVerts );
	// RELEASE_DRX( m_pBackBuffer ); ?
}

void CRenderMaster::Shutdown( void )
{
	UnregisterEvents( );
	ShutdownDeferred( );

	RELEASE_DRX( m_pSphereMesh );
	RELEASE_DRX( m_pCylinderMesh );
	RELEASE_DRX( m_pShapesDecl );
	RELEASE_DRX( m_pDebugShapes );

	m_AssetManager.Shutdown( );

	RELEASE_DRX( m_pDev );
	RELEASE_DRX( m_pD3D );
}

//////////////////////////////
// REMOVE FROM HERE ON
void CRenderMaster::DRAWTROGDOR( void )
{
	ID3DXEffect* pEffect = m_AssetManager.GetShader( 0 );
	if( pEffect )
	{
		// Begin the shader!
		pEffect->SetTechnique( "Basic" );
		unsigned int nNumPasses = 0;
		pEffect->Begin( &nNumPasses, 0 );

		D3DXMATRIX triMatrix;
		D3DXMatrixIdentity( &triMatrix );
		D3DXMatrixRotationY( &triMatrix, globalRotate * 3 );

		// Loop through the passes
		for( unsigned int i = 0; i < nNumPasses; ++i )
		{
			pEffect->BeginPass( i );

			// Send any data to the shader
			pEffect->SetMatrix( "gWVP", &( triMatrix * m_Camera.GetView( ) * m_Camera.GetProjection( ) ) );
			pEffect->SetMatrix( "World", &triMatrix );
			//pEffect->SetTexture( "imageTexture", m_AssetManager.GetMesh( 0 )->pTexture );
			pEffect->CommitChanges( );

			m_pDev->SetVertexDeclaration( m_AssetManager.trogdorDecl );
			m_pDev->SetStreamSource( 0, m_AssetManager.GetMesh( 0 )->pVertBuffer, 0, sizeof( TROGTEX ) );
			m_pDev->SetIndices( m_AssetManager.GetMesh( 0 )->pIndexBuffer );
			m_pDev->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, m_AssetManager.GetMesh( 0 )->nNumVerts, 0, m_AssetManager.GetMesh( 0 )->nNumTris );

			pEffect->EndPass( );
		}

		// We're done with the shader!
		pEffect->End( );
	}
}

void CRenderMaster::GetInput( void )
{
	static bool bPressed1 = false;
	static bool bPressed2 = false;
	static bool bPressed3 = false;
	static bool bPressed4 = false;

	if( GetAsyncKeyState( 'I' ) && bPressed1 == false )
	{
		HRESULT hr = D3DXSaveSurfaceToFile( "Color.png", D3DXIFF_PNG, m_pColorSurface, NULL, NULL );
		
		bPressed1 = true;
	}
	else
		bPressed1 = false;

	if( GetAsyncKeyState( 'O' ) && bPressed2 == false )
	{
		HRESULT hr = D3DXSaveSurfaceToFile( "Normal.png", D3DXIFF_PNG, m_pNormalSurface, NULL, NULL );
		
		bPressed2 = true;
	}
	else
		bPressed2 = false;

	if( GetAsyncKeyState( 'P' ) && bPressed3 == false )
	{
		HRESULT hr = D3DXSaveSurfaceToFile( "Depth.png", D3DXIFF_PNG, m_pDepthSurface, NULL, NULL );
		
		bPressed3 = true;
	}
	else
		bPressed3 = false;

	if( GetAsyncKeyState( 'L' ) && bPressed4 == false )
	{
		HRESULT hr = D3DXSaveSurfaceToFile( "Light.png", D3DXIFF_PNG, m_pLightSurface, NULL, NULL );
		
		bPressed4 = true;
	}
	else
		bPressed4 = false;

	if( GetAsyncKeyState( VK_DOWN ) )
		m_Camera.ViewTranslateLocalZ( 0.01f );
	else if( GetAsyncKeyState( VK_UP ) )
		m_Camera.ViewTranslateLocalZ( -0.01f );

	if( GetAsyncKeyState( VK_RIGHT ) )
		m_Camera.ViewRotateLocalY( 0.001f );
	else if( GetAsyncKeyState( VK_LEFT ) )
		m_Camera.ViewRotateLocalY( -0.001f );

	if( GetAsyncKeyState( 'W' ) )
		m_Camera.ViewTranslateLocalY( -0.01f );
	else if( GetAsyncKeyState( 'S' ) )
		m_Camera.ViewTranslateLocalY( 0.01f );
}
